/*
 * Copyright (c) 2010, Michael Hengler (developer (at) hengler (dot) de),
 * Nikolaus Moll (developer (at) miblounge (dot) net).
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * * Neither the name of the Jombi project nor the
 * names of its contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL JOMBI BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */
package net.miblounge.jombi.impl.widgets;

import java.util.List;

import net.miblounge.jombi.impl.layout.LayoutManagerImpl;
import net.miblounge.jombi.impl.util.DecorationCalc;
import net.miblounge.jombi.impl.widgets.util.ChildRemover;
import net.miblounge.miglayout.qt.MigLayout;

import org.jowidgets.common.color.IColorConstant;
import org.jowidgets.common.types.Cursor;
import org.jowidgets.common.types.Dimension;
import org.jowidgets.common.types.Position;
import org.jowidgets.common.types.Rectangle;
import org.jowidgets.common.widgets.IControlCommon;
import org.jowidgets.common.widgets.IWidgetCommon;
import org.jowidgets.common.widgets.controller.IComponentListener;
import org.jowidgets.common.widgets.controller.IFocusListener;
import org.jowidgets.common.widgets.controller.IKeyListener;
import org.jowidgets.common.widgets.controller.IMouseListener;
import org.jowidgets.common.widgets.controller.IPopupDetectionListener;
import org.jowidgets.common.widgets.descriptor.IWidgetDescriptor;
import org.jowidgets.common.widgets.factory.ICustomWidgetCreator;
import org.jowidgets.common.widgets.factory.ICustomWidgetFactory;
import org.jowidgets.common.widgets.factory.IGenericWidgetFactory;
import org.jowidgets.common.widgets.layout.ILayoutDescriptor;
import org.jowidgets.common.widgets.layout.ILayouter;
import org.jowidgets.common.widgets.layout.MigLayoutDescriptor;
import org.jowidgets.spi.widgets.IContainerSpi;
import org.jowidgets.spi.widgets.IPopupMenuSpi;
import org.jowidgets.util.Assert;

import com.trolltech.qt.core.QObject;
import com.trolltech.qt.gui.QLayout;
import com.trolltech.qt.gui.QToolBar;
import com.trolltech.qt.gui.QWidget;

public class QtContainer implements IContainerSpi {

	private final IGenericWidgetFactory factory;
	private final QWidget container;
	private final QtComponent qtComponentDelegate;

	public QtContainer(final IGenericWidgetFactory factory, final QWidget container) {
		Assert.paramNotNull(factory, "factory");

		this.factory = factory;
		this.container = container;
		this.qtComponentDelegate = new QtComponent(container);
	}

	@Override
	public void setLayout(final ILayoutDescriptor layout) {
		Assert.paramNotNull(layout, "layout");

		if (layout instanceof MigLayoutDescriptor) {
			final MigLayoutDescriptor migLayoutManager = (MigLayoutDescriptor) layout;

			// check if there is a layout manager already
			if (!(getUiReference().layout() instanceof MigLayout)) {
				if (getUiReference().layout() != null) {
					getUiReference().layout().dispose();
				}

				// create a new layout
				getUiReference().setLayout(new MigLayout());
			}

			final MigLayout migLayout = (MigLayout) getUiReference().layout();

			migLayout.setLayoutConstraints(migLayoutManager.getLayoutConstraints());
			migLayout.setColumnConstraints(migLayoutManager.getColumnConstraints());
			migLayout.setRowConstraints(migLayoutManager.getRowConstraints());
		} else if (layout instanceof ILayouter) {
			if (container.layout() != null) {
				container.layout().dispose();
			}
			container.setLayout(new LayoutManagerImpl(getUiReference(), (ILayouter) layout));
		} else {
			throw new IllegalArgumentException("Layout Manager of type '" + layout.getClass().getName() + "' is not supported");
		}
	}

	@Override
	public QWidget getUiReference() {
		return container;
	}

	@Override
	public void redraw() {
		qtComponentDelegate.redraw();
	}

	@Override
	public void setForegroundColor(final IColorConstant colorValue) {
		qtComponentDelegate.setForegroundColor(colorValue);
	}

	@Override
	public IColorConstant getForegroundColor() {
		return qtComponentDelegate.getForegroundColor();
	}

	@Override
	public void setBackgroundColor(final IColorConstant colorValue) {
		qtComponentDelegate.setBackgroundColor(colorValue);
	}

	@Override
	public IColorConstant getBackgroundColor() {
		return qtComponentDelegate.getBackgroundColor();
	}

	@Override
	public <WIDGET_TYPE extends IControlCommon> WIDGET_TYPE add(
		final Integer index,
		final IWidgetDescriptor<? extends WIDGET_TYPE> descriptor,
		final Object layoutConstraints) {
		final WIDGET_TYPE result = factory.create(getUiReference(), descriptor);
		if (!(result instanceof QToolBar)) {
			addToContainer(index, result, layoutConstraints);
		}
		return result;
	}

	@Override
	public <WIDGET_TYPE extends IControlCommon> WIDGET_TYPE add(
		final Integer index,
		final ICustomWidgetCreator<WIDGET_TYPE> creator,
		final Object layoutConstraints) {
		final ICustomWidgetFactory customWidgetFactory = createCustomWidgetFactory();

		final WIDGET_TYPE result = creator.create(customWidgetFactory);
		addToContainer(index, result, layoutConstraints);
		return result;
	}

	@Override
	public boolean remove(final IControlCommon control) {
		return ChildRemover.removeChild(container, (QWidget) control.getUiReference());
	}

	@Override
	public void removeAll() {
		final QLayout layout = getUiReference().layout();

		// remove from layout
		while (layout.count() > 0) {
			layout.takeAt(0);
		}

		// remove children
		for (final QObject child : getUiReference().children()) {
			if (child.isWidgetType()) {
				final QWidget widget = (QWidget) child;
				widget.setParent(null);
				widget.close();
			}
		}
	}

	@Override
	public void layoutBegin() {
		getUiReference().setUpdatesEnabled(false);
	}

	@Override
	public void layoutEnd() {
		getUiReference().setUpdatesEnabled(true);
	}

	protected IGenericWidgetFactory getGenericWidgetFactory() {
		return factory;
	}

	private ICustomWidgetFactory createCustomWidgetFactory() {
		return new ICustomWidgetFactory() {
			@Override
			public <WIDGET_TYPE extends IControlCommon> WIDGET_TYPE create(
				final IWidgetDescriptor<? extends WIDGET_TYPE> descriptor) {
				return factory.create(getUiReference(), descriptor);
			}
		};
	}

	protected void addToContainer(final Integer index, final IWidgetCommon widget, final Object cellConstraints) {
		// TODO NM index
		if (getUiReference().layout() instanceof MigLayout) {
			final MigLayout layout = (MigLayout) getUiReference().layout();
			if (widget.getUiReference() instanceof QWidget) {
				layout.addWidget((QWidget) widget.getUiReference(), cellConstraints);
			}
		} else if (getUiReference().layout() instanceof LayoutManagerImpl) {
			final LayoutManagerImpl layout = (LayoutManagerImpl) getUiReference().layout();
			if (widget.getUiReference() instanceof QWidget) {
				layout.addLayoutComponent((QWidget) widget.getUiReference(), cellConstraints);
			}
		} else {
			throw new IllegalArgumentException("Layout Manager in class "
				+ getUiReference().getClass()
				+ " of type '"
				+ getUiReference().layout().getClass().getName()
				+ "' is not supported");
		}
	}

	@Override
	public void setVisible(final boolean visible) {
		qtComponentDelegate.setVisible(visible);
	}

	@Override
	public boolean isVisible() {
		return qtComponentDelegate.isVisible();
	}

	@Override
	public Dimension getSize() {
		return qtComponentDelegate.getSize();
	}

	@Override
	public void setCursor(final Cursor cursor) {
		qtComponentDelegate.setCursor(cursor);
	}

	@Override
	public void setEnabled(final boolean enabled) {
		qtComponentDelegate.setEnabled(enabled);
	}

	@Override
	public boolean isEnabled() {
		return qtComponentDelegate.isEnabled();
	}

	@Override
	public IPopupMenuSpi createPopupMenu() {
		return qtComponentDelegate.createPopupMenu();
	}

	@Override
	public void addPopupDetectionListener(final IPopupDetectionListener listener) {
		qtComponentDelegate.addPopupDetectionListener(listener);
	}

	@Override
	public void removePopupDetectionListener(final IPopupDetectionListener listener) {
		qtComponentDelegate.removePopupDetectionListener(listener);
	}

	@Override
	public Position getPosition() {
		return qtComponentDelegate.getPosition();
	}

	@Override
	public void setPosition(final Position position) {
		qtComponentDelegate.setPosition(position);
	}

	@Override
	public void setSize(final Dimension size) {
		qtComponentDelegate.setSize(size);
	}

	@Override
	public void setRedrawEnabled(final boolean enabled) {
		qtComponentDelegate.setRedrawEnabled(enabled);
	}

	@Override
	public boolean requestFocus() {
		return qtComponentDelegate.requestFocus();
	}

	@Override
	public void addFocusListener(final IFocusListener listener) {
		qtComponentDelegate.addFocusListener(listener);
	}

	@Override
	public void removeFocusListener(final IFocusListener listener) {
		qtComponentDelegate.removeFocusListener(listener);
	}

	@Override
	public void addKeyListener(final IKeyListener listener) {
		qtComponentDelegate.addKeyListener(listener);
	}

	@Override
	public void removeKeyListener(final IKeyListener listener) {
		qtComponentDelegate.removeKeyListener(listener);
	}

	@Override
	public void addComponentListener(final IComponentListener componentListener) {
		qtComponentDelegate.addComponentListener(componentListener);
	}

	@Override
	public void removeComponentListener(final IComponentListener componentListener) {
		qtComponentDelegate.removeComponentListener(componentListener);
	}

	@Override
	public void addMouseListener(final IMouseListener mouseListener) {
		qtComponentDelegate.addMouseListener(mouseListener);
	}

	@Override
	public void removeMouseListener(final IMouseListener mouseListener) {
		qtComponentDelegate.removeMouseListener(mouseListener);
	}

	@Override
	public Rectangle getClientArea() {
		return DecorationCalc.getClientArea(getUiReference());
	}

	@Override
	public Dimension computeDecoratedSize(final Dimension clientAreaSize) {
		Assert.paramNotNull(clientAreaSize, "clientAreaSize");
		return DecorationCalc.computeDecoratedSize(container, clientAreaSize);
	}

	@Override
	public void setTabOrder(final List<? extends IControlCommon> tabOrder) {
		// TODO NM implement

	}

}
